home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / wnos / wn941101 / icmp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-10  |  6.5 KB  |  266 lines

  1. /* Internet Control Message Protocol (ICMP)
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include <stdio.h>
  5. #include "global.h"
  6. #include "mbuf.h"
  7. #include "timer.h"
  8. #include "iface.h"
  9. #include "ip.h"
  10. #include "icmp.h"
  11. #include "netuser.h"
  12.  
  13. struct mib_entry Icmp_mib[] = {
  14.     "",                        0,
  15.     "InMsgs",            0,
  16.     "InErrors",            0,
  17.     "InDestUnreachs",    0,
  18.     "InTimeExcds",        0,
  19.     "InParmProbs",        0,
  20.     "InSrcQuenchs",        0,
  21.     "InRedirects",        0,
  22.     "InEchos",            0,
  23.     "InEchoReps",        0,
  24.     "InTimestamps",        0,
  25.     "InTimestampReps",    0,
  26.     "InAddrMasks",        0,
  27.     "InAddrMaskReps",    0,
  28.     "OutMsgs",            0,
  29.     "OutErrors",        0,
  30.     "OutDestUnreachs",    0,
  31.     "OutTimeExcds",        0,
  32.     "OutParmProbs",        0,
  33.     "OutSrcQuenchs",    0,
  34.     "OutRedirects",        0,
  35.     "OutEchos",            0,
  36.     "OutEchoReps",        0,
  37.     "OutTimestamps",    0,
  38.     "OutTimestampReps",    0,
  39.     "OutAddrMasks",        0,
  40.     "OutAddrMaskReps",    0,
  41. };
  42.  
  43. /* Process an incoming ICMP packet */
  44. void
  45. icmp_input(iface,ip,bp,rxbroadcast)
  46. struct iface *iface;    /* Incoming interface (ignored) */
  47. struct ip *ip;        /* Pointer to decoded IP header structure */
  48. struct mbuf *bp;    /* Pointer to ICMP message */
  49. int rxbroadcast;
  50. {
  51.     struct icmplink *ipp;
  52.     struct mbuf *tbp;
  53.     struct icmp icmp;    /* ICMP header */
  54.     struct ip oip;        /* Offending datagram header */
  55.     unsigned char type;            /* Type of ICMP message */
  56.     int16 length;
  57.  
  58.     icmpInMsgs++;
  59.  
  60.     if(rxbroadcast){
  61.         /* Broadcast ICMP packets are to be IGNORED !! */
  62.         icmpInErrors++;
  63.         free_p(bp);
  64.         return;
  65.     }
  66.  
  67.     if(cksum(NULLHEADER,bp,length = (ip->length - IPLEN - ip->optlen)) != 0){
  68.         /* Bad ICMP checksum; discard */
  69.         icmpInErrors++;
  70.         free_p(bp);
  71.         return;
  72.     }
  73.     ntohicmp(&icmp,&bp);
  74.  
  75.     /* Process the message. Some messages are passed up to the protocol
  76.      * module for handling, others are handled here.
  77.      */
  78.     type = uchar(icmp.type);
  79.  
  80.     switch(type){
  81.     case ICMP_TIME_EXCEED:    /* Time-to-live Exceeded */
  82.     case ICMP_DEST_UNREACH:    /* Destination Unreachable */
  83.     case ICMP_QUENCH:    /* Source Quench */
  84.         switch(type){
  85.         case ICMP_TIME_EXCEED:    /* Time-to-live Exceeded */
  86.             icmpInTimeExcds++;
  87.             break;
  88.         case ICMP_DEST_UNREACH:    /* Destination Unreachable */
  89.             icmpInDestUnreachs++;
  90.             break;
  91.         case ICMP_QUENCH:    /* Source Quench */
  92.             icmpInSrcQuenchs++;
  93.             break;
  94.         }
  95.         ntohip(&oip,&bp);    /* Extract offending IP header */
  96.         if(Icmp_trace){
  97.             tprintf("ICMP from %s: ",inet_ntoa(ip->source));
  98.             tprintf("dest %s ",inet_ntoa(oip.dest));
  99.             tprintf("%s ",smsg(Icmptypes,ICMP_TYPES,type));
  100.             switch(type){
  101.             case ICMP_TIME_EXCEED:
  102.                 tprintf("%s\n",smsg(Exceed,NEXCEED,uchar(icmp.code)));
  103.                 break;
  104.             case ICMP_DEST_UNREACH:
  105.                 tprintf("%s\n",smsg(Unreach,NUNREACH,uchar(icmp.code)));
  106.                 break;
  107.             default:
  108.                 tprintf("%u\n",uchar(icmp.code));
  109.                 break;
  110.             }
  111.         }
  112.         for(ipp = Icmplink; ipp->funct != NULL; ipp++)
  113.             if(ipp->proto == oip.protocol)
  114.                 break;
  115.         if(ipp->funct != NULL){
  116.           (*ipp->funct)(ip->source,oip.source,oip.dest,icmp.type,icmp.code,&bp);
  117.         }
  118.         break;
  119.     case ICMP_ECHO:        /* Echo Request */
  120.         /* Change type to ECHO_REPLY, recompute checksum,
  121.          * and return datagram.
  122.          */
  123.         icmpInEchos++;
  124.         icmp.type = ICMP_ECHO_REPLY;
  125.         if((tbp = htonicmp(&icmp,bp)) == NULLBUF){
  126.             free_p(bp);
  127.             return;
  128.         }
  129.         icmpOutEchoReps++;
  130.         ip_send(ip->dest,ip->source,ICMP_PTCL,ip->tos,0,tbp,length,0,0);
  131.         return;
  132.     case ICMP_REDIRECT:    /* Redirect */
  133.         icmpInRedirects++;
  134.         break;
  135.     case ICMP_PARAM_PROB:    /* Parameter Problem */
  136.         icmpInParmProbs++;
  137.         break;
  138.     case ICMP_ECHO_REPLY:    /* Echo Reply */
  139.         icmpInEchoReps++;
  140.         echo_proc(ip->source,ip->dest,&icmp,bp);
  141.         bp = NULLBUF;    /* so it won't get freed */
  142.         break;
  143.     case ICMP_TIMESTAMP:    /* Timestamp */
  144.         icmpInTimestamps++;
  145.         break;
  146.     case ICMP_TIME_REPLY:    /* Timestamp Reply */
  147.         icmpInTimestampReps++;
  148.         break;
  149.     case ICMP_INFO_RQST:    /* Information Request */
  150.         break;
  151.     case ICMP_INFO_REPLY:    /* Information Reply */
  152.         break;
  153.     }
  154.     free_p(bp);
  155. }
  156. /* Return an ICMP response to the sender of a datagram.
  157.  * Unlike most routines, the callER frees the mbuf.
  158.  */
  159. int
  160. icmp_output(ip,data,type,code,args)
  161. struct ip *ip;        /* Header of offending datagram */
  162. struct mbuf *data;    /* Data portion of datagram */
  163. char type,code;        /* Codes to send */
  164. union icmp_args *args;
  165. {
  166.     struct mbuf *bp = NULLBUF;
  167.     struct icmp icmp;    /* ICMP protocol header */
  168.     int16 dlen;            /* Length of data portion of offending pkt */
  169.     int16 length;        /* Total length of reply */
  170.  
  171.     if(ip == NULLIP)
  172.         return -1;
  173.     if(uchar(ip->protocol) == ICMP_PTCL){
  174.         /* Peek at type field of ICMP header to see if it's safe to
  175.          * return an ICMP message
  176.          */
  177.         switch(uchar(data->data[0])){
  178.         case ICMP_ECHO_REPLY:
  179.         case ICMP_ECHO:
  180.         case ICMP_TIMESTAMP:
  181.         case ICMP_TIME_REPLY:
  182.         case ICMP_INFO_RQST:
  183.         case ICMP_INFO_REPLY:
  184.             break;    /* These are all safe */
  185.         default:
  186.             /* Never send an ICMP error message about another
  187.              * ICMP error message!
  188.              */
  189.             return -1;
  190.         }
  191.     }
  192.     /* Compute amount of original datagram to return.
  193.      * We return the original IP header, and up to 8 bytes past that.
  194.      */
  195.     if((dlen = len_p(data)) > 8)
  196.         dlen = 8;
  197.     length = dlen + ICMPLEN + IPLEN + ip->optlen;
  198.  
  199.     /* Take excerpt from data portion */
  200.     if(data != NULLBUF && dup_p(&bp,data,0,dlen) == 0)
  201.         return -1;    /* The caller will free data */
  202.  
  203.     /* Recreate and tack on offending IP header */
  204.     if((data = htonip(ip,bp,0)) == NULLBUF){
  205.         free_p(bp);
  206.         icmpOutErrors++;
  207.         return -1;
  208.     }
  209.     icmp.type = type;
  210.     icmp.code = code;
  211.     icmp.args.unused = 0;
  212.     switch(uchar(icmp.type)){
  213.     case ICMP_PARAM_PROB:
  214.         icmpOutParmProbs++;
  215.         icmp.args.pointer = args->pointer;
  216.         break;
  217.     case ICMP_REDIRECT:
  218.         icmpOutRedirects++;
  219.         icmp.args.address = args->address;
  220.         break;
  221.     case ICMP_ECHO:
  222.         icmpOutEchos++;
  223.         break;
  224.     case ICMP_ECHO_REPLY:
  225.         icmpOutEchoReps++;
  226.         break;
  227.     case ICMP_INFO_RQST:
  228.         break;
  229.     case ICMP_INFO_REPLY:
  230.         break;
  231.     case ICMP_TIMESTAMP:
  232.         icmpOutTimestamps++;
  233.         break;
  234.     case ICMP_TIME_REPLY:
  235.         icmpOutTimestampReps++;
  236.         icmp.args.echo.id = args->echo.id;
  237.         icmp.args.echo.seq = args->echo.seq;
  238.         break;
  239.     case ICMP_ADDR_MASK:
  240.         icmpOutAddrMasks++;
  241.         break;
  242.     case ICMP_ADDR_MASK_REPLY:
  243.         icmpOutAddrMaskReps++;
  244.         break;
  245.     case ICMP_DEST_UNREACH:
  246.         if(icmp.code == ICMP_FRAG_NEEDED)
  247.             icmp.args.mtu = args->mtu;
  248.         icmpOutDestUnreachs++;
  249.         break;
  250.     case ICMP_TIME_EXCEED:
  251.         icmpOutTimeExcds++;
  252.         break;
  253.     case ICMP_QUENCH:
  254.         icmpOutSrcQuenchs++;
  255.         break;
  256.     }
  257.     icmpOutMsgs++;
  258.  
  259.     /* Now stick on the ICMP header */
  260.     if((bp = htonicmp(&icmp,data)) == NULLBUF){
  261.         free_p(data);
  262.         return -1;
  263.     }
  264.     return ip_send(INADDR_ANY,ip->source,ICMP_PTCL,ip->tos,0,bp,length,0,0);
  265. }
  266.